package xyz.yuzegod.megawalls.tellraw;

import net.minecraft.server.v1_8_R3.IChatBaseComponent;
import net.minecraft.server.v1_8_R3.Packet;
import net.minecraft.server.v1_8_R3.PacketPlayOutChat;
import org.bukkit.Bukkit;
import org.bukkit.command.CommandSender;
import org.bukkit.craftbukkit.v1_8_R3.entity.CraftPlayer;
import org.bukkit.entity.Player;
import org.bukkit.inventory.ItemStack;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class Tellraw implements Cloneable
{
    private List<MessagePart> messageParts;
    private String cache;
    
    public Tellraw(final String text) {
        (this.messageParts = new ArrayList<MessagePart>()).add(new MessagePart(text));
    }
    
    public static Tellraw create() {
        return create("");
    }
    
    public static Tellraw create(final String text) {
        return new Tellraw(text);
    }
    
    public static Tellraw create(final String text, final Object... objects) {
        return new Tellraw(String.format(text, objects));
    }
    
    public void broadcast() {
        for (final Player player : Bukkit.getOnlinePlayers()) {
            this.send((CommandSender)player);
        }
    }
    
    public Tellraw cmd_tip(final String command, final String... tip) {
        return this.command(command).tip(tip);
    }
    
    public Tellraw command(final String command) {
        return this.onClick("run_command", command);
    }
    
    public Tellraw file(final String path) {
        return this.onClick("open_file", path);
    }
    
    public Tellraw insertion(final String data) {
        this.latest().insertionData = data;
        return this;
    }
    
    public Tellraw item(final ItemStack item) {
        return this.item(ItemSerialize.$(item));
    }
    
    public Tellraw item(final String json) {
        return this.onHover("show_item", json);
    }
    
    public Tellraw link(final String url) {
        return this.onClick("open_url", url);
    }
    
    public Tellraw openurl(final String url) {
        return this.onClick("open_url", url);
    }
    
    public void send(final CommandSender sender) {
        final String json = this.toJsonString();
        if (sender instanceof Player && json.getBytes().length < 32000) {
            final IChatBaseComponent comp = IChatBaseComponent.ChatSerializer.a(json);
            final PacketPlayOutChat packet = new PacketPlayOutChat(comp);
            ((CraftPlayer)sender).getHandle().playerConnection.sendPacket((Packet)packet);
        }
        else {
            sender.sendMessage(this.toOldMessageFormat());
        }
    }
    
    public Tellraw sug_tip(final String command, final String... tip) {
        return this.suggest(command).tip(tip);
    }
    
    public Tellraw suggest(final String command) {
        return this.onClick("suggest_command", command);
    }
    
    public Tellraw text(final String text) {
        this.latest().text = text;
        return this;
    }
    
    public Tellraw then(final String text) {
        return this.then(new MessagePart(text));
    }
    
    public Tellraw then(final String name, final ItemStack item) {
        return this.then(name).item(ItemSerialize.$(item));
    }
    
    public Tellraw then(final String text, final Object... objects) {
        return this.then(new MessagePart(String.format(text, objects)));
    }
    
    public Tellraw tip(final List<String> texts) {
        if (texts.isEmpty()) {
            return this;
        }
        final StringBuilder text = new StringBuilder();
        for (final String t : texts) {
            text.append(t).append("\n");
        }
        return this.tip(text.toString().substring(0, text.length() - 1));
    }
    
    public Tellraw tip(final String text) {
        return this.onHover("show_text", text);
    }
    
    public Tellraw tip(final String... texts) {
        return this.tip(Arrays.asList(texts));
    }
    
    public String toJsonString() {
        if (this.cache == null) {
            final StringBuilder msg = new StringBuilder();
            msg.append("[\"\"");
            for (final MessagePart messagePart : this.messageParts) {
                msg.append(",");
                messagePart.writeJson(msg);
            }
            msg.append("]");
            this.cache = msg.toString();
        }
        return this.cache;
    }
    
    public Tellraw setMessageParts(final List<MessagePart> messageParts) {
        this.messageParts = new ArrayList<MessagePart>(messageParts);
        return this;
    }
    
    public Tellraw clone() throws CloneNotSupportedException {
        return ((Tellraw)super.clone()).setMessageParts(this.messageParts);
    }
    
    public String toOldMessageFormat() {
        final StringBuilder result = new StringBuilder();
        for (final MessagePart part : this.messageParts) {
            result.append(part.text);
        }
        return result.toString();
    }
    
    private MessagePart latest() {
        return this.messageParts.get(this.messageParts.size() - 1);
    }
    
    private Tellraw onClick(final String name, final String data) {
        final MessagePart latest = this.latest();
        latest.clickActionName = name;
        latest.clickActionData = data;
        return this;
    }
    
    private Tellraw onHover(final String name, final String data) {
        final MessagePart latest = this.latest();
        latest.hoverActionName = name;
        latest.hoverActionData = data;
        return this;
    }
    
    private Tellraw then(final MessagePart part) {
        final MessagePart last = this.latest();
        if (!last.hasText()) {
            last.text = part.text;
        }
        else {
            this.messageParts.add(part);
        }
        this.cache = null;
        return this;
    }
}
